package com.cictec.middleware.tde.rm.mina.filter;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.tde.rm.protocol.TerminalMessage;
import com.cictec.middleware.tde.rm.protocol.rm.ProtocelConstants;
import com.cictec.middleware.tde.rm.protocol.rm.SendSequenceGenerator;
import com.cictec.middleware.tde.rm.protocol.rm.message.Rm0x06TerminalMessage;

/**
 * 当平台收到一个设备上传的反馈信息时，自动寻找平台下发的原始消息。
 * 
 * @author Zhibin
 *
 */
@Component
public class SendMonitorFilter extends IoFilterAdapter {
	
	private static Logger logger = LoggerFactory.getLogger(SendMonitorFilter.class);
	
	//正在等待终端响应的消息。
	private final AttributeKey WAITTING_RESPONSE_MESSAGES = new AttributeKey(getClass(), "waittingResponseMessage");
	
	private final Integer TERMINAL_RESPONSE_MESSAGE_ID = 0X06;
	
	private Set<Integer> needResponseMessages;
	
	
	public SendMonitorFilter(){
		Set<Integer> needResponseMessages = new HashSet<Integer>();
		needResponseMessages.add(0x81);
		setNeedResponseMessages(needResponseMessages);
		
		
		if(logger.isDebugEnabled()){
			String str = null;
			for (Integer integer : needResponseMessages) {
				String messageId = PMSUtils.addZeroLForString(String.valueOf(Integer.toHexString(integer)), 2);
				str = str == null ? "0x"+messageId : str + ",0x"+messageId;
			}
			if(str != null){
				logger.debug("【SendMonitorFilter】【锐明】 设置服务器需要回复的消息指令集  {}", str);
			}
		}
	}
	
	/**
	 * 如果平台收到的是设备反馈消息。则在session的“等待反馈消息”队列中找相对应的原始消息，并将原始消息的ID附加到终端反馈消息上。
	 */
	@Override
	public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
		
		TerminalMessage msg = (TerminalMessage)message;
		if(msg.getHeader().getMessageId() == TERMINAL_RESPONSE_MESSAGE_ID){
			//如果是发送指令的响应消息
			Rm0x06TerminalMessage tgr = (Rm0x06TerminalMessage)msg;
			//找到该Session等待响应的消息。
			//等待响应的消息是一个队列。
			BlockingQueue<TerminalMessage> waittingForResponseMessages = (BlockingQueue<TerminalMessage>)session.getAttribute(WAITTING_RESPONSE_MESSAGES);
			if(waittingForResponseMessages != null){
				TerminalMessage wpTm = waittingForResponseMessages.poll();
				while(wpTm != null){
					if(tgr.getResponseMessageId() == wpTm.getHeader().getMessageId() 
							&& tgr.getResponseSequence() == wpTm.getHeader().getMessageSequence()){
						tgr.setOriginalMessageUuid(wpTm.getUuid());
						break;
					}
					wpTm = waittingForResponseMessages.poll();
				}
			}
			
		}
		nextFilter.messageReceived(session, message);
	}

	/**
	 *发送一个消息对象的时候做两个事情。
	 * 1.为消息增加流水号；
	 * 2.如果该消息是必须终端反馈，那么将该消息写入到session的“等待反馈消息”队列中。
	 */
	@Override
	public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
		
		TerminalMessage tm = (TerminalMessage)writeRequest.getMessage();
		//增加消息头的流水号
		SendSequenceGenerator sequenceGenerator = (SendSequenceGenerator) session.getAttribute(ProtocelConstants.SESSION_SEND_SEQUENCE);
		int sendSequence = sequenceGenerator.getNextValue();
		tm.getHeader().setMessageSequence(sendSequence);
		
		if(needResponseMessages.contains(tm.getHeader().getMessageId())){
			BlockingQueue<TerminalMessage> waittingForResponseMessages = (BlockingQueue<TerminalMessage>)session.getAttribute(WAITTING_RESPONSE_MESSAGES);
			if(waittingForResponseMessages == null){
				waittingForResponseMessages = new LinkedBlockingQueue<TerminalMessage>();
				session.setAttribute(WAITTING_RESPONSE_MESSAGES,waittingForResponseMessages);
			}
			waittingForResponseMessages.offer(tm);
		}

		nextFilter.filterWrite(session, writeRequest);
		
	}

	public Set<Integer> getNeedResponseMessages() {
		return needResponseMessages;
	}

	public void setNeedResponseMessages(Set<Integer> needResponseMessages) {
		this.needResponseMessages = needResponseMessages;
	}
	
}
